# Game.py: Alien Xenocide main module
# Written by Victor Luna Freire - victorclf@live.com
# Copyright (c) Victor Luna Freire. All rights reserved.
# Sunday, June 04, 2009 00:00:00 PM
# Python 2.6.2

import os
import sys
import pygame
import random

import Sprites
import Gameobjects
import Timer
import Input
import Raycaster
import Maps
import Weapons
import Defines
import Stars
import ScreenFX
import Shared
import Renderer
import Gamescript
import Sound
import Maze

import Menu
import Builder

try:
    import psyco
    psyco.full()
except ImportError:
    print "Performance Warning: psyco not available"
    pass

class FPS_counter:
    def __init__(self):
        self.frames = 0
    def average(self):
        return self.frames / (pygame.time.get_ticks() / 1000.)


class Game(Menu.Menu, Builder.Builder):
    def __init__(self):
        ''' Initializes the game data and modules. '''

        Sound.Sound.pre_init()       
        
        # Pygame initialization
        pygame.init()
        
        pygame.mixer.set_num_channels(32)
        pygame.mixer.music.set_volume(1.0)
        # Sound init        
        Sound.Sound.load_sounds()
                
        # Set window caption and icon
        pygame.display.set_caption(Defines.WINDOW_TITLE)
        icon = pygame.image.load(os.path.join('data', 'sprites', 'ax.png'))
        if icon: pygame.display.set_icon(icon)
        else: warn("Failed to load window icon!")
    
        screen_flags = Defines.SCREEN_FLAGS
        if len(sys.argv) > 1 and sys.argv[1] == '-fullscreen':
            screen_flags = pygame.FULLSCREEN
        # Pygame display configuration
        try:
            self.screen = pygame.display.set_mode((Defines.SCREEN_WIDTH, Defines.SCREEN_HEIGHT), screen_flags, Defines.SCREEN_BPP)
        except pygame.error, msg:
            print "Error: failed to initialize display -", msg
                
        # Hide mouse
        pygame.mouse.set_visible(False)
        
        # Sprites Manager
        Sprites.Sprites.load_sprites()
                
        # Raycasting renderer
        self.Raycaster = Raycaster.RaycasterClass(Defines.PROJECTION_WIDTH, Defines.PROJECTION_HEIGHT)
        
        # The Player
        self.player = Gameobjects.Player((Defines.MAP_START_POS_X, Defines.MAP_START_POS_Y), 45)
        
        # The Guns
        #self.Weapons = Weapons.Weapons()
                
        # Setup map system(map system loads stuff automatically)
        Maps.Maps.set_current_map('map0')
        
        # Load the States
        Menu.Menu.__init__(self)
        Builder.Builder.__init__(self)
        
        # Timer multiply factor
        self.mult_factor = 0
        # Creates the state stack
        self.state = [self.main_menu] 
        
        Sound.Sound.play_music('menu')
        Gamescript.SoundDirector.sound_event('titlecall')
        self.reset_menu()
                
        self.hud_font = pygame.font.SysFont('ALIEN5.TTF',26)
        self.hud_font2 = pygame.font.SysFont('ALIEN5.TTF',32)
        self.hud_deck_surface = self.hud_font.render("DECK", True, (255,255,255))
        
        # Display new game tutorial?
        self.tutorial = Defines.NEW_GAME_TUTORIAL
        self.objects = []

    def shutdown(self):
        pygame.quit()
        
    
    def new_game(self):
        #Maps.Maps.maps = {}
        #Maps.Maps.objects = {}
        #Maps.Maps.load_maps()
        self.found_exit = False
        mazecopy = Maze.Maze.get_maze_copy()
        mazecopy[-1][-2] = 'Z' #exit
        Maps.Maps.load_temp_map(mazecopy)
        self.reset_menu()
        Sound.Sound.play_music('maze')
        #self.Weapons.recharge()
        self.player.health = self.player.max_health
        Gamescript.GameDirector.new_game(self.player)
        self.state.append(self.game)
        self.death_time_elapsed = 0
        self.compass_variation = random.randint(0, 359)
        if(Defines.NEW_GAME_TUTORIAL):
            self.tutorial = True
            Sprites.Sprites.get_sprite('ui\\fasttutorial').set_alpha(210)


    def game(self):
        if not self.handle_input(self.mult_factor):
            Sound.Sound.play_music('menu')
            return False
        
        # Handle monsters
        
        #objects = Gamescript.GameDirector.objects
        #for o in objects:
        #    o.main(self.player, self.mult_factor, self.time_variation)

        # Hand with compass
        self.screen.fill((0, 0, 0)) #clear screen
        self.Raycaster.render_scene(self.screen, self.player, self.objects)
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\compass'), (250, 200))
                
        # The compass needle
        needlesprite = Sprites.Sprites.get_sprite('ui\\needle')
        orig_rect = needlesprite.get_rect()
        orig_rect.topleft = 480, 289
                
        needlerotated = pygame.transform.rotate(needlesprite, (360 - self.player.angle) + self.compass_variation)
        rect = needlerotated.get_rect(center=orig_rect.center)
        self.screen.blit(needlerotated, rect)
        
        '''
        center = self.rect.center
        self.dizzy += 12
        if self.dizzy >= 360:
            self.dizzy = 0
            self.image = self.original
        else:
            rotate = pygame.transform.rotate
            self.image = rotate(self.original, self.dizzy)
        self.rect = self.image.get_rect(center=center)
        '''

        
        
        if self.found_exit: self.screen.blit(Sprites.Sprites.get_sprite('menu\\enddoor'), (0, 0))
        #self.Weapons.draw(self.screen)
        #self.draw_hud()
        
        #ScreenFX.ShieldHit.main(self.screen, self.mult_factor)
        
        #if self.tutorial:
        #    self.screen.blit(Sprites.Sprites.get_sprite('ui\\fasttutorial'), (0, 0))
        
        #if self.player.health < 1:
        #    if not(ScreenFX.BloodDeath.finished or ScreenFX.BloodDeath.running):
        #        ScreenFX.BloodDeath.reset()
        #    
        #    ScreenFX.BloodDeath.update()
        #    ScreenFX.BloodDeath.draw(self.screen)
        #    
        #    self.death_time_elapsed += self.time_variation
        #    if self.death_time_elapsed > Defines.DEAD_SCREEN_TIME:
        #        Sound.Sound.play_music('menu')
        #        return False
                
        pygame.display.flip()
        return True
        
        
    def draw_hud(self):
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\barra_status'), (0, Defines.SCREEN_HEIGHT - 80))
        
        self.screen.blit(self.hud_deck_surface, (570,408))
        self.screen.blit(self.hud_font2.render(str(Gamescript.GameDirector.current_map + 1), True, (255,255,255)), (587,432))
        
        shield_y = 408
        shieldbar_x = 65
        shieldbar_y = 410
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shield'), (17, shield_y))
        self.screen.fill((0,0,0), (shieldbar_x, shieldbar_y, 299, 30))
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shieldbar'), (65, shieldbar_y), (0, 0, 300 * (self.player.health / float(self.player.max_health)), 30))
        
        shellbox_y = 443
        shells_x = 65
        shells_y = 445
        shell_width = 8
        shell_proportion = 2
        self.screen.blit(Sprites.Sprites.get_sprite('ui\\shellbox'), (10, shells_y))
        self.screen.fill((0,0,0), (shells_x, shells_y+1, shell_width * (self.Weapons.current_weapon.max_ammo / shell_proportion) + 1, 29))
        shell_sprite = Sprites.Sprites.get_sprite('ui\\shotshell')
        for i in xrange(0, self.Weapons.current_weapon.ammo, 2): self.screen.blit(shell_sprite, (shells_x + ((i/shell_proportion)*8), shells_y + 2))
        
        
    def interact_map(self):
        gridposplayer = Renderer.togridF(self.player.x, self.player.y)
        for xvar in xrange(-1, 2):
            for yvar in xrange(-1, 2):
                gridpos = (gridposplayer[0] + xvar, gridposplayer[1] + yvar)
                if Maps.Maps.is_valid_grid(gridpos):
                    wid = Maps.Maps.world[gridpos[1]][gridpos[0]]
                    if wid == '0':   #empty space
                        continue
                    elif wid == 'Z': #level exit
                        Sound.Sound.play_music('victory')
                        self.found_exit = True
                        #Gamescript.GameDirector.found_exit(self.player)
                        return
                    elif wid == 'W': #loaded recharge station
                        #Maps.Maps.world[gridpos[1]][gridpos[0]] = 'X' #empty this station
                        #Gamescript.SoundDirector.sound_event('recharge')
                        #self.player.health = self.player.max_health
                        #self.Weapons.recharge()
                        return
                                            
    def handle_input(self, mult_factor):
        keep_running = Input.Input.get_input()
        
        if Input.Input.keys:
            self.tutorial = False
        
        if Input.Input.check_once(pygame.K_ESCAPE):
            keep_running = False
        
        
        #Is the Player alive?
        if self.player.health < 1 or self.found_exit: return keep_running
        
        mult_factor_run = mult_factor
        if Input.Input.check(pygame.K_LSHIFT):
            mult_factor *= 2  # player running?
            mult_factor_run *= 1.3  # player running?
        
        if Input.Input.check(pygame.K_UP):
            self.player.move_forward(mult_factor_run)
            
        if Input.Input.check(pygame.K_DOWN):
            self.player.move_backward(mult_factor_run)
            
        if Input.Input.check(pygame.K_LEFT):
            if Input.Input.check(pygame.K_LALT):
                self.player.strafe_left(mult_factor_run)
            else:
                self.player.turn_left(mult_factor)

        if Input.Input.check(pygame.K_RIGHT):
            if Input.Input.check(pygame.K_LALT):
                self.player.strafe_right(mult_factor_run)
            else:
                self.player.turn_right(mult_factor)
        
        #if Input.Input.check(pygame.K_LCTRL):
        #    self.Weapons.fire(self.Raycaster.enemies_in_aim)
        #
        if Input.Input.check_once(pygame.K_SPACE):
            self.interact_map()
            
        #if Input.Input.check_once(pygame.K_p) and Defines.MONSTEREDIT:
        #    MonsterEditor.addp1((self.player.x, self.player.y))
        #
        #if Input.Input.check_once(pygame.K_l) and Defines.MONSTEREDIT:
        #    MonsterEditor.addp2((self.player.x, self.player.y))
        #
        #if Input.Input.check_once(pygame.K_n) and Defines.MONSTEREDIT:
        #    Gamescript.GameDirector.found_exit(self.player)
        
        return keep_running


def main():
    game = Game() # creates the game object and initializes the modules
    while game.state:
        game.mult_factor = Timer.Timer.get_mult_factor()
        game.time_variation = Timer.Timer.get_time_variation()
        if not game.state[-1]():
            game.state.pop()
        Timer.Timer.update()
    game.shutdown()   # cleans up before exitting
    print "Thanks for playing Graphaze."    

main()
